// 核心思想
// 条款14的核心思想是：当设计管理资源的类时，必须特别注意该类的复制行为。不恰当的复制可能导致资源泄漏、重复释放或其他未定义行为。
class Lock
{
private:
    Mutex *mutexPtr;

public:
    explicit Lock(Mutex *pm) : mutexPtr(pm)
    {
        lock(mutexPtr); // 获取互斥锁
    }

    ~Lock()
    {
        unlock(mutexPtr); // 释放互斥锁
    }
};

// 使用Lock类
Mutex m;
{
    Lock lock1(&m);    // 锁定互斥锁
    Lock lock2(lock1); // 复制lock1 - 这里会发生什么？编译器为我们构造了一个拷贝构造函数
} // lock1和lock2都被销毁

// 策略1：禁止复制（C++11后）
class Lock
{
private:
    Mutex *mutexPtr;

public:
    explicit Lock(Mutex *pm) : mutexPtr(pm) { lock(mutexPtr); }
    ~Lock() { unlock(mutexPtr); }

    // 使用=delete明确禁止复制
    Lock(const Lock &) = delete;
    Lock &operator=(const Lock &) = delete;
};

// 策略2：使用引用计数（共享语义）
class Lock
{
private:
    std::shared_ptr<Mutex> mutexPtr; // 使用shared_ptr管理引用计数

public:
    explicit Lock(Mutex *pm)
        : mutexPtr(pm, unlock) // 自定义删除器
    {
        lock(mutexPtr.get());
    }

    // 不需要析构函数，shared_ptr会在引用计数为0时自动调用unlock
};
// 策略3：复制底层资源（深拷贝）
class Lock
{
private:
    Mutex *mutexPtr;

public:
    explicit Lock(Mutex *pm) : mutexPtr(pm) { lock(mutexPtr); }
    ~Lock() { unlock(mutexPtr); }

    // 深拷贝 - 为每个复制品获取一个新的互斥锁
    Lock(const Lock &other) : mutexPtr(new Mutex(*other.mutexPtr))
    {
        lock(mutexPtr);
    }

    Lock &operator=(const Lock &other)
    {
        if (this != &other)
        {
            unlock(mutexPtr);                      // 释放当前锁
            mutexPtr = new Mutex(*other.mutexPtr); // 复制互斥锁
            lock(mutexPtr);                        // 锁定新的互斥锁
        }
        return *this;
    }
};

// 策略4：转移所有权（C++11移动语义）
class Lock
{
private:
    Mutex *mutexPtr;

public:
    explicit Lock(Mutex *pm) : mutexPtr(pm) { lock(mutexPtr); }
    ~Lock()
    {
        if (mutexPtr)
            unlock(mutexPtr);
    }

    // 禁止复制
    Lock(const Lock &) = delete;
    Lock &operator=(const Lock &) = delete;

    // 允许移动
    Lock(Lock &&other) noexcept : mutexPtr(other.mutexPtr)
    {
        other.mutexPtr = nullptr; // 防止原对象释放资源
    }

    Lock &operator=(Lock &&other) noexcept
    {
        if (this != &other)
        {
            if (mutexPtr)
                unlock(mutexPtr);      // 释放当前资源
            mutexPtr = other.mutexPtr; // 获取新资源
            other.mutexPtr = nullptr;  // 防止原对象释放资源
        }
        return *this;
    }
};

// 3. 现代C++中的最佳实践
class Lock
{
private:
    // 这确实是一个高级的C++写法，让我来详细解释它：
    // std::unique_ptr<Mutex, decltype(&unlock)> mutexPtr;
    // 这行代码定义了一个特殊的std::unique_ptr智能指针，它不仅管理Mutex对象的内存，还使用自定义的删除器（deleter）来释放资源。让我们逐部分分析：

    // 1. std::unique_ptr<T, Deleter>
    // std::unique_ptr是一个模板类，接受两个模板参数：

    // T：被管理的对象类型
    // Deleter：删除器类型（可选，默认为std::default_delete<T>）
    // 默认情况下，unique_ptr使用delete运算符释放内存。但对于非内存资源（如互斥锁、文件句柄等），我们需要自定义删除器。

    // 2. decltype(&unlock)
    // decltype是C++ 11引入的关键字，用于获取表达式的类型。
    // 在这里， &unlock是函数unlock的地址，而decltype(&unlock) 则获取这个函数指针的类型。
    // 假设unlock函数的签名是：
    // void unlock(Mutex* m);
    // 那么decltype(&unlock)的结果就是void(*)(Mutex*)，即一个接受Mutex*参数并返回void的函数指针类型。

    // 3. 完整解析
    // 结合起来，std::unique_ptr<Mutex, decltype(&unlock)>表示：
    // 一个管理Mutex对象的智能指针
    // 当需要释放资源时，不是调用delete，而是调用unlock函数

    std::unique_ptr<Mutex, decltype(&unlock)> mutexPtr;

public:
    explicit Lock(Mutex *pm)
        : mutexPtr(pm, unlock) // 自定义删除器
    {
        lock(pm);
    }

    // unique_ptr默认禁止复制，允许移动
    // 无需手动定义复制/移动构造函数和赋值运算符
};
void unlock(Mutex *m) { /* 释放互斥锁 */ }

class SharedLock
{
private:
    std::shared_ptr<Mutex> mutexPtr;

public:
    explicit SharedLock(Mutex *pm)
        : mutexPtr(pm, [](Mutex *m)
                   { unlock(m); }) // 使用lambda作为删除器
    {
        lock(pm);
    }

    // shared_ptr默认允许复制，实现共享语义
    // 无需手动定义复制构造函数和赋值运算符
};

// 4. 常见陷阱和注意事项
// 1)忘记处理自赋值：在赋值运算符中，必须处理a = a的情况
Lock &operator=(const Lock &other)
{
    if (this == &other)
        return *this; // 自赋值检查
    // 其他赋值逻辑...
}

// 2)异常安全性：确保在复制过程中发生异常时不会泄漏资源
Lock &operator=(const Lock &other)
{
    Mutex *tempMutex = new Mutex(*other.mutexPtr); // 可能抛出异常
    lock(tempMutex);                               // 可能抛出异常

    unlock(mutexPtr); // 只有在上面的操作成功后才释放旧资源
    mutexPtr = tempMutex;

    return *this;
}

// 复制语义与资源特性不匹配：某些资源本质上不应该被复制（如文件句柄）
// 混合使用智能指针和裸指针：容易导致重复释放或悬空指针

// 5. 实际应用建议
// 优先考虑禁止复制：很多资源管理类本质上不应该被复制
// 如需复制，优先使用智能指针：让标准库处理复杂的引用计数逻辑
// 明确表达意图：使用= delete、= default或显式实现，清晰表达设计意图
// 考虑移动语义：C++11后，提供移动操作通常比复制更高效
// 保持一致性：复制构造函数和赋值运算符应该实现相同的语义
// 总结
// 条款14强调了在设计资源管理类时必须谨慎处理复制行为。根据资源的特性和使用场景，可以选择禁止复制、实现引用计数、执行深拷贝或支持移动语义。在现代C++中，标准库的智能指针（std::unique_ptr和std::shared_ptr）提供了简洁而强大的工具来实现这些策略，大大简化了资源管理类的设计。

// 记住：资源管理类的复制行为必须与其管理的资源特性相匹配，这是编写安全、可靠的C++代码的关键部分。